/*
**************************************************************************************************************
File:         controller.sv
Description:  Functions as a partial controller - based on inputs, sends signals to interface
Author     :  Katerina Gleeson
**************************************************************************************************************
*/

`include "package.sv"

/*-----------------------------------------------------------------------------------------------------
                            MODULE CONTROLLER
-------------------------------------------------------------------------------------------------------
*/
module controller(DDR_bus IF, input logic OP, input logic [LOGICAL_ADDR_WIDTH-1:0] ADDR, input logic start, output logic done);


wire [DATA_WIDTH-1:0] data;
logic [COL_WIDTH-1:0] column;   //7bits 6:0
logic [ROW_WIDTH-1:0] row;      //7bits 13:7 
logic [BANK_ADDR_WIDTH-1:0] bank;
bit issue_auto_refresh;
integer count = 0;
integer count_cyc = 0;
logic [DATA_WIDTH-1:0] data_received;


logic [8:0] State, NextState;
logic DQS_level = HIGH;
//assign IF.DQ = data_received;

/*------ State Declarations ------------*/
parameter RESET       = 9'b000000001,
          IDLE        = 9'b000000010,
          EXTRACT     = 9'b000000100,
          ACTIVATE    = 9'b000001000,
          READ        = 9'b000010000,
          WRITE       = 9'b000100000,
          VALID_DATA  = 9'b001000000,
          PRECHARGE   = 9'b010000000,
          AUTO_REFRESH= 9'b100000000;


assign IF.DQS = (IF.WE ? 'Z : DQS_level);


//Update refresh counter at every clock tick
always_ff @(posedge IF.CK)
begin
  if(count === 0)
  begin  
    count <= REFRESH_COUNT_LIMIT; 
    issue_auto_refresh = 1;
  end
  else
  begin
    count <= count - 1;
    issue_auto_refresh = 0;
  end
end

// counter for state transitions
always_ff @(posedge IF.CK)
begin
  if(start)
    begin
      if(count_cyc == (tRC + tEXTRACT))
        count_cyc <= 0;
      else
        count_cyc <= count_cyc + 1;
    end
  else
    count_cyc <= 0;
end

//Update state
always_ff @(posedge IF.CK)
begin
  if(IF.rst)
    State <= RESET;
  else
    State <= NextState;
end

always_ff @(IF.CK)
begin
  if(State == VALID_DATA)
    DQS_level = ~DQS_level;
end

//Next State logic
always_comb
begin
  case(State)
  RESET:  begin
            if(~IF.rst)
              begin
				      if(start)
					       NextState = EXTRACT;
				      else
					      NextState = RESET;
					      end
            else      
              NextState = RESET;              
          end 
  
  IDLE:   begin
            if(count == 0)
              NextState <= AUTO_REFRESH;
            else      
            begin
               if(start)
                 NextState =   EXTRACT;
               else
                 NextState =   IDLE;
            end
          end
  
  EXTRACT:  begin
            if(count == 0)
              NextState <= AUTO_REFRESH;
            else  
              NextState = ACTIVATE;                        
            end	

            	
  ACTIVATE: begin
              if(count == 0)
                NextState <= AUTO_REFRESH;
              else
              begin
                if(count_cyc == (tRCD + tEXTRACT)) 
				begin
					if(OP == 0)
						NextState = READ;                        
					else
						NextState = WRITE;
				end
				else
					NextState = ACTIVATE;
              end      
            end
  
  READ:       begin
              if(count == 0)
                NextState <= AUTO_REFRESH;
              else
			  begin
					if(count_cyc == (tRCD + tCL + tEXTRACT))
						NextState = VALID_DATA;  
					else
						NextState = READ;
              end
			  end

  WRITE:      begin
              if(count == 0)
                NextState <= AUTO_REFRESH;
              else
              begin
					if(count_cyc == (tRCD + tCL + tEXTRACT))
						NextState = VALID_DATA;  
					else
						NextState = WRITE;
              end  
              end
  
  VALID_DATA: begin
              if(count == 0)
                NextState <= AUTO_REFRESH;
              else
			  begin
                if(count_cyc == (tRAS + tEXTRACT))
					NextState = PRECHARGE;
				else
					NextState = VALID_DATA;
              end
			  end

  PRECHARGE:    begin
                if(count == 0)
                  NextState <= AUTO_REFRESH;
                else
				begin
					if(count_cyc == (tRAS + tRP + tEXTRACT))
						NextState = IDLE;  
					else
						NextState = PRECHARGE;  
                end
				end

  AUTO_REFRESH: begin   
                  NextState <= IDLE;                                    
                end
endcase
end


//Output logic
always_comb
begin
  case(State)
  RESET:      begin
                done = 0;
			         	IF.dis_write();            //disable write enable
			         	IF.deassert_DRAM_data_out();
			         	IF.disable_chip();
              end 
  
  IDLE :	     begin
            				done = 1;
            				IF.deassert_pins();
            				IF.deassert_DRAM_data_out();
            				if(~start)
          				    IF.disable_chip();
            			end
            			
  EXTRACT:    begin
                done = 0;
                IF.extract_rbc(ADDR, row, bank, column);
                IF.deassert_DRAM_data_out();
                IF.enable_chip();
              end      	
  
  ACTIVATE:  begin
    				        done = 0;
    				        IF.activate(bank,row);
    				        IF.deassert_DRAM_data_out();
             end

  PRECHARGE:  begin
                done = 0;
                IF.precharge_single_bank(bank);
                IF.deassert_DRAM_data_out();
              end 
  
  READ:       begin
                done = 0;
                IF.read(bank, column);   
                IF.deassert_DRAM_data_out();
              end
  
  VALID_DATA: begin
                done = 0;
                IF.valid_data(OP,data_received);
                IF.set_DRAM_data_out(OP);
              end
  
  WRITE:	     begin
                done = 0;
                IF.write(bank, column);   
                IF.deassert_DRAM_data_out();
              end

  AUTO_REFRESH:begin
                done = 0;
                IF.deassert_DRAM_data_out();
      			      end
endcase
end


endmodule

